package com.kancy.delay.queue.redis.key;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;

import java.util.Objects;

/**
 * <p>
 * DefaultRedisKeyResolver
 * <p>
 *
 * @author: kancy
 * @date: 2020/3/5 0:05
 **/
public class DefaultRedisKeyResolver implements RedisKeyResolver, ApplicationContextAware {
    private static final String DEFAULT_PROJECT_NAME = "default";
    private static final String DEFAULT_SLOT_KEY_PREFIX = "{key}";

    private ApplicationContext applicationContext;

    private String project;

    /**
     * Redis cluster对多key操作有限，要求命令中所有的key都属于一个slot，才可以被执行。
     * {hash-key}key
     */
    private String slotKeyPrefix;

    public DefaultRedisKeyResolver() {
    }

    public DefaultRedisKeyResolver(String project) {
        this.project = project;
    }

    /**
     * 获取延时队列的z-set redis key
     *
     * @param topic
     * @return
     */
    @Override
    public String bucketKey(String topic) {
        return key(String.format("%s:delay:queue:bucket:%s", getProject(), topic));
    }

    /**
     * 获取消息hashtable redis key
     *
     * @param topic
     * @return
     */
    @Override
    public String hashTableKey(String topic) {
        return key(String.format("%s:delay:queue:message:%s", getProject(),topic));
    }

    /**
     * 集群环境下，保持key在同一个slot上
     *
     * @param key
     * @return
     */
    @Override
    public String key(String key) {
        return String.format("%s%s", getSlotKeyPrefix(), key);
    }

    /**
     * 获取project
     * @return
     */
    private String getSlotKeyPrefix() {
        if (Objects.isNull(this.slotKeyPrefix)) {
            synchronized (this){
                if (Objects.isNull(this.slotKeyPrefix)){
                    Environment environment = applicationContext.getEnvironment();
                    if (environment.containsProperty("spring.redis.cluster.nodes")){
                        this.slotKeyPrefix = environment.getProperty("delay.queue.slot-key-prefix",
                                environment.getProperty("delay.queue.slotKeyPrefix", DEFAULT_SLOT_KEY_PREFIX));
                        if (!(this.slotKeyPrefix.startsWith("{") && this.slotKeyPrefix.endsWith("}"))){
                            this.slotKeyPrefix = String.format("{%s}", this.slotKeyPrefix);
                        }
                    }else{
                        this.slotKeyPrefix = "";
                    }
                }
            }
        }
        return this.slotKeyPrefix;
    }

    /**
     * 获取project
     * @return
     */
    private String getProject() {
        if (Objects.isNull(this.project)) {
            synchronized (this){
                if (Objects.isNull(this.project)){
                    Environment environment = applicationContext.getEnvironment();
                    this.project = environment.getProperty("delay.queue.project",
                            environment.getProperty("spring.application.name", DEFAULT_PROJECT_NAME));
                }
            }
        }
        return this.project;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
}
